package top.cyixlq.chat.utils

import android.content.Context
import android.text.TextUtils
import android.util.Log
import kotlinx.coroutines.*
import org.json.JSONObject
import top.cyixlq.chat.entity.MessageBean
import java.io.*
import java.net.ServerSocket
import java.net.Socket

object SocketManager {

    private const val TAG = "SocketManager"
    private const val CHAR_SET = "UTF-8"

    private lateinit var nickName: String
    private var listener: ((MessageBean) -> Unit)? = null // 回调监听
    private val clients = LinkedHashSet<Socket>() // 连接到服务器的客户端
    private var server: ServerSocket? = null // 服务端
    private var serverJob: Job? = null
    private var client: Socket? = null // 客户端
    private var clientOut: PrintStream? = null // 客户端发送
    private var clientJob: Job? = null

    /* ----------------------- 客户端处理 ------------------------- */
    fun connectServer(ip: String, context: Context, nickName: String?) {
        this.nickName = nickName ?: IPUtil.getIPAddress(context)
        clientJob = GlobalScope.launch(Dispatchers.IO) {
            try {
                client = Socket(ip, 9090)
                client?.let {
                    invokeMessage(MessageBean(true, "服务器已连接：${ip}:9090", "系统提示"))
                    val clientIn = BufferedReader(InputStreamReader(it.getInputStream(), CHAR_SET))
                    clientOut = PrintStream(it.getOutputStream())
                    while (isActive) {
                        val json = clientIn.readLine()
                        invokeMessage(json.toMessageBean())
                    }
                }
            } catch (e: Exception) {
                val msg = "连接服务端失败：${e.message}"
                Log.e(TAG, msg)
                invokeMessage(MessageBean(true, msg, "系统提示"))
            } finally {
                release()
            }
        }
    }

    fun sendToServer(msg: String) {
        GlobalScope.launch(Dispatchers.IO) {
            clientOut?.println(MessageBean(true, msg, nickName).toJson())
        }
    }

    /* ----------------------- 服务器端处理 ------------------------- */
    fun startServer(context: Context, nickName: String?) {
        this.nickName = nickName ?: IPUtil.getIPAddress(context)
        serverJob = GlobalScope.launch(Dispatchers.IO) {
            try {
                server = ServerSocket(9090) // 创建服务器
                while (isActive) {
                    val client = server?.accept() ?: continue
                    clients.add(client)
                    observeClient(client)
                    val bean = MessageBean(true, "${client.inetAddress.hostAddress}加入聊天", "系统提示")
                    invokeMessage(bean)
                    pushAll(client, bean)
                }
            } catch (e: Exception) {
                val msg = "服务器创建失败：${e.message}"
                Log.d(TAG, msg)
                invokeMessage(MessageBean(true, msg, "系统提示"))
            }
        }
    }

    fun serverSendMsg(msg: String) {
        pushAll(null, MessageBean(true, msg, nickName))
    }

    private fun observeClient(client: Socket) {
        GlobalScope.launch(Dispatchers.IO) {
            while (isActive) {
                if (client.isClosed || !client.isConnected) {
                    clients.remove(client)
                    break
                }
                try {
                    val ins = BufferedReader(InputStreamReader(client.getInputStream(), CHAR_SET))
                    val json = ins.readLine()
                    if (!TextUtils.isEmpty(json)) {
                        val bean = json.toMessageBean()
                        invokeMessage(bean)
                        pushAll(client, bean)
                    }
                } catch (ignore: Exception) {
                    clients.remove(client)
                    break
                }
            }
        }
    }

    // 服务端将接收到的消息推送给全部客户端
    private fun pushAll(send: Socket?, bean: MessageBean) {
        for (client in clients) {
            if (client.isClosed || !client.isConnected) {
                clients.remove(client)
                continue
            }
            if (client == send) { // 如果遍历到是发送方，就不给他推消息了
                continue
            }
            GlobalScope.launch(Dispatchers.IO) {
                val out = PrintWriter(OutputStreamWriter(client.getOutputStream(), CHAR_SET), true)
                out.println(bean.toJson())
            }
        }
    }

    private suspend fun invokeMessage(msgBean: MessageBean) {
        withContext(Dispatchers.Main) {
            listener?.invoke(msgBean)
        }
    }

    fun setOnMessageListener(listener: (MessageBean) -> Unit) {
        this.listener = listener
    }

    fun removeOnMessageListener() {
        this.listener = null
    }

    fun release() {
        for (client in clients) {
            if (!client.isClosed)
                client.close()
        }
        server?.let {
            if (!it.isClosed)
                it.close()
        }
        serverJob?.cancel()
        client?.let {
            if (!it.isClosed)
                it.close()
        }
        clientJob?.cancel()
        listener = null
    }

}